package collections;

public class DualNodeList <T> implements Collectionable<T> {
	private DualNode first;
	private DualNode last;
	private int count;
	private class DualNode{

		private DualNode nextNode;
		private DualNode prevNode;
		private T value;
		public DualNode(T val, DualNode prev, DualNode next){
			value = val;
			prevNode = prev;
			nextNode = next;
		}
		void setPrev(DualNode prev){
			prevNode = prev;
		}
		DualNode getPrev(){
			return prevNode;
		}
		void setNext(DualNode next){
			nextNode = next;
		}
		DualNode getNext(){
			return nextNode;
		}
		T getVal(){
			return value;
		}
		
	}
	public int getCount(){return count;}
	private DualNode getNodeAt(int index){
		if (index<count/2){
			DualNode curr = first;
			for(int i = 0;i<index;--i){
				curr = curr.getNext();
			}
			return curr;
		}
		else{
			DualNode curr = last;
			for(int i = count-1;i>index;--i){
				curr = curr.getNext();
			}
			return curr;
		}
		
	}
	public T elementAt(int index){
		if (index<count && index>=0){return getNodeAt(index).getVal();}
		else return (T) null;
	}
	public void add(T val){
		last = new DualNode(val,last,null);
		if(count==0){
			first = last;
		}else{
			last.getPrev().setNext(last);
		}
		++count;
	}
	public void insert(T val, int index){
		if (count == index){
			add(val);
			return;
		}
		if (index==0){
			first.setPrev(new DualNode(val,null,first));
			first = first.getPrev();
			++count;
		}else if(index<count&&index>0){
			DualNode next = getNodeAt(index);
			next.getPrev().setNext(new DualNode(val,next.getPrev(),next));
			next.setPrev(next.getPrev().getNext());
			++count;
		}
		else System.out.println("Wrong index.");
	}
	public void remove(int index){
		if(index<0||index>=count) return;
		if(index==0){first=first.getNext();}
		else{
			DualNode rem = getNodeAt(index);
			rem.getPrev().setNext(rem.getNext());
			rem.getNext().setPrev(rem.getPrev());
		}
		--count;
	}
	public void printValues(){
		DualNode curr = first;
		while (curr!=null){
			System.out.println(curr.getVal()+", ");
			curr=curr.getNext();
		}
	}
	public void clearAll(){
		first = null;
		last = null;
		count = 0;
	}
	private class Iterator implements Iteratorable<T>{
		private DualNode curr;
		@Override
		public boolean moveNext() {
			if (curr == null){
				curr=first;
				return (curr == null)?false:true;
			}else{
				if(curr.getNext()==null){
					return false;
				}else{
					curr=curr.getNext();
					return true;
				}
			}
		}

		@Override
		public T getCurrent() {
			// TODO Auto-generated method stub
			return curr.getVal();
		}
		
	}
	@Override
	public Iteratorable<T> getIterator (){
		return new Iterator();
	}
	@Override
	public Collectionable<T> where(Queryable<T> q) {
		DualNodeList<T> res = new DualNodeList<T>();
		Iteratorable<T> it=this.getIterator();
		while (it.moveNext()){
			if(q.check(it.getCurrent())){
				res.add(it.getCurrent());
			}
		}
		return res;
	}
}
